package com.engine.jucailinkq.attendance.attendanceanalysis.cmd.getclockInpoint;

import com.alibaba.fastjson.JSONObject;
import com.engine.jucailinkq.attendance.attendanceanalysis.dto.clockpoint.ClockPointDTO;
import com.engine.jucailinkq.attendance.enums.AccountingUnitEnum;
import com.engine.jucailinkq.attendance.enums.CheckBoxEnum;
import com.engine.jucailinkq.attendance.enums.ClassSegmentTypeEnum;
import com.engine.jucailinkq.attendance.enums.ClockPointEnum;
import com.engine.common.biz.AbstractCommonCommand;
import com.engine.common.entity.BizLogContext;
import com.engine.jucailinkq.common.util.DateUtil;
import com.engine.jucailinkq.common.util.Utils;
import com.engine.core.interceptor.CommandContext;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import weaver.general.BaseBean;
import weaver.general.Util;

import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 根据卡点、打卡时间将卡点和打卡时间一一对应
 */
@Slf4j
public class GetClockInPointCmd extends AbstractCommonCommand<Map<String, Object>> {
    public GetClockInPointCmd(Map<String, Object> params) {
        this.params = params;
    }


    /**
     * 需要打卡的卡点
     */
    private List<String> needClockDateList;
    /**
     * 分析日期
     */
    private String analysisDate;

    @Override
    public BizLogContext getLogContext() {
        return null;
    }

    @Override
    public Map<String, Object> execute(CommandContext commandContext) {
        Map<String, Object> resultMap = Maps.newHashMap();

        BaseBean baseBean = new BaseBean();
        baseBean.writeLog("GetClockInPointCmd params:" + JSONObject.toJSONString(params));
        String analysisDate = Util.null2String(params.get("analysisDate"));
        this.analysisDate=analysisDate;
        List<Map<String, Object>> scheduleResult = (List<Map<String, Object>>) params.get("scheduleResult");
        List<Map<String, Object>> clockInTimeList = (List<Map<String, Object>>) params.get("clockInTimeList");
        List<Map<String, Object>> askForLeaveAndEvctionScheduleList = (List<Map<String, Object>>) params.get("askForLeaveAndEvctionSchedule");
        List<Map<String, Object>> needClockInList = scheduleResult.stream().filter(e -> !ClassSegmentTypeEnum.REST_AND_DINE.getKey().equals(e.get("bdlx")) && !ClassSegmentTypeEnum.REST_PERIOD.getKey().equals(e.get("bdlx")) &&
                !ClassSegmentTypeEnum.DINING_PERIOD.getKey().equals(e.get("bdlx")) ).collect(Collectors.toList());

        log.debug("未重新计算卡点时 老的scheduleResult : [{}],askForLeaveAndEvctionScheduleList:[{}]",scheduleResult,askForLeaveAndEvctionScheduleList);

        //调整加班计时间段的打卡
        scheduleResult = adjustWorkOverTimeClock(scheduleResult,analysisDate);
        //调整请假出差时间段的打卡
        askForLeaveAndEvctionScheduleList = adjustAskforSchedule(scheduleResult,analysisDate,askForLeaveAndEvctionScheduleList);
        log.debug("经过adjustWorkOverTimeClock 加班调整过后的 的scheduleResult: [{}]",scheduleResult);

        /**
         * 当请假或外出开始时间和外出时间在上班之外时，不需要打卡
         */
        //判断是否骑在上班卡或下班卡
        boolean ifStartNeedClock=false;
        String startNeedClockTime = "";
        boolean ifEndNeedClock=false;
        String endNeedClockTime = "";
        if (needClockInList.size() > 0 && askForLeaveAndEvctionScheduleList.size() > 0) {
            String startTime = Utils.getkssjTime(needClockInList.get(0),analysisDate);
            String endStartTime  = Utils.getkssjTime(needClockInList.get(needClockInList.size()-1),analysisDate);
            String endTime  = Utils.getjssjTime(needClockInList.get(needClockInList.size()-1),analysisDate);

            for (Map<String, Object> askForLeaveAndEvctionSchedule :askForLeaveAndEvctionScheduleList){
                String dtkssj = Utils.getkssjTime(askForLeaveAndEvctionSchedule,analysisDate);
                String dtjssj = Utils.getjssjTime(askForLeaveAndEvctionSchedule,analysisDate);

                if (DateUtil.getTime(dtkssj).compareTo(DateUtil.getTime(startTime))<=0 || DateUtil.getTime(dtkssj).compareTo(DateUtil.getTime(endTime)) >= 0){
                    askForLeaveAndEvctionSchedule.put("ksdk",CheckBoxEnum.UNCHECKED.getKey());
                }
                if (DateUtil.getTime(dtjssj).compareTo(DateUtil.getTime(endTime))>=0 || DateUtil.getTime(dtjssj).compareTo(DateUtil.getTime(startTime))<=0){
                    askForLeaveAndEvctionSchedule.put("jsdk",CheckBoxEnum.UNCHECKED.getKey());
                }

                if (DateUtil.getTime(dtkssj).compareTo(DateUtil.getTime(startTime))<=0 && DateUtil.getTime(dtjssj).compareTo(DateUtil.getTime(endTime))<0 && DateUtil.getTime(dtjssj).compareTo(DateUtil.getTime(startTime)) >0){
                    //骑在开始上班时间
                    for (Map<String,Object> needClockMap:needClockInList){
                        String kssj = Utils.getkssjTime(needClockMap,analysisDate);
                        String jssj  = Utils.getjssjTime(needClockMap,analysisDate);

                        //中间只要有开始打卡，即上班需要打卡
                        if (CheckBoxEnum.CHECKED.getKey().equals(needClockMap.get("ksdk")) && DateUtil.getTime(dtjssj).compareTo(DateUtil.getTime(jssj)) >=0){
                            ifStartNeedClock=true;
                            startNeedClockTime = dtjssj;
                        }
                    }
                }

                if (DateUtil.getTime(dtkssj).compareTo(DateUtil.getTime(startTime)) > 0 && DateUtil.getTime(dtjssj).compareTo(DateUtil.getTime(endTime))>=0 && DateUtil.getTime(dtkssj).compareTo(DateUtil.getTime(endTime)) < 0){
                    //骑在下班时间
                    for (Map<String,Object> needClockMap:needClockInList){
                        String kssj = Utils.getkssjTime(needClockMap,analysisDate);
                        //中间只要有结束打卡，即下班需要打卡
                        if (CheckBoxEnum.CHECKED.getKey().equals(needClockMap.get("jsdk")) && DateUtil.getTime(dtkssj).compareTo(DateUtil.getTime(kssj)) <=0){
                            ifEndNeedClock=true;
                            endNeedClockTime = dtkssj;
                        }
                    }
                }

            }
        }

        /**
         * 当请假或外出包含打卡卡点时，判断该卡点是否需要打卡
         */
        for (Map<String, Object> askForLeaveAndEvctionMap :askForLeaveAndEvctionScheduleList){
            String evctiondtkssj = Utils.getkssjTime(askForLeaveAndEvctionMap,analysisDate);
            String evctionksdk = Util.null2String(askForLeaveAndEvctionMap.get("ksdk"));
            String evctiondtjssj = Utils.getjssjTime(askForLeaveAndEvctionMap,analysisDate);
            String evctionjsdk = Util.null2String(askForLeaveAndEvctionMap.get("jsdk"));
            String zysd = Util.null2String(askForLeaveAndEvctionMap.get("zysd"));

            List<String> lists = Lists.newArrayList();
            for (int i=0;i<scheduleResult.size();i++){
                String dtkssj = Utils.getkssjTime(scheduleResult.get(i),analysisDate);
                String dtjssj = Utils.getjssjTime(scheduleResult.get(i),analysisDate);
                String bdlx = Util.null2String(scheduleResult.get(i).get("bdlx"));
                if (zysd.contains(Utils.getWorkFor(bdlx))){
                    if (DateUtil.getTime(evctiondtkssj).compareTo(DateUtil.getTime(dtkssj)) <= 0 && DateUtil.getTime(evctiondtjssj).compareTo(DateUtil.getTime(dtkssj)) >=0
                            && !ClassSegmentTypeEnum.REST_AND_DINE.getKey().equals(bdlx) && !ClassSegmentTypeEnum.REST_PERIOD.getKey().equals(bdlx) && !ClassSegmentTypeEnum.DINING_PERIOD.getKey().equals(bdlx)){
                        lists.add(dtkssj+"&"+ClockPointEnum.START.getKey()+"&"+Util.null2String(scheduleResult.get(i).get("ksdk")));
                    }
                    if (DateUtil.getTime(evctiondtkssj).compareTo(DateUtil.getTime(dtjssj)) <= 0 && DateUtil.getTime(evctiondtjssj).compareTo(DateUtil.getTime(dtjssj)) >=0
                            && !ClassSegmentTypeEnum.REST_AND_DINE.getKey().equals(bdlx) && !ClassSegmentTypeEnum.REST_PERIOD.getKey().equals(bdlx) && !ClassSegmentTypeEnum.DINING_PERIOD.getKey().equals(bdlx)){
                        lists.add(dtjssj+"&"+ClockPointEnum.END.getKey()+"&"+Util.null2String(scheduleResult.get(i).get("jsdk")));
                    }
                }
            }
            //新打卡
            List<String> newNeedClockLists = Lists.newArrayList();
            //时间-结束卡\开始卡-是否打卡
            if (lists.size() == 1){
                String str = lists.get(0);
                if (ClockPointEnum.START.getKey().equals(str.split("&")[1]) && CheckBoxEnum.CHECKED.getKey().equals(evctionjsdk)){
                    newNeedClockLists.add(str.split("&")[0]+"&"+str.split("&")[1]+"&0");
                }else if (ClockPointEnum.END.getKey().equals(str.split("&")[1]) && CheckBoxEnum.CHECKED.getKey().equals(evctionksdk)){
                    newNeedClockLists.add(str.split("&")[0]+"&"+str.split("&")[1]+"&0");
                }
            }else if (lists.size() > 1){
                for(int i=0;i<lists.size();i++){
                    String str = lists.get(i);
                    if (i ==0){
                        if (CheckBoxEnum.CHECKED.getKey().equals(evctionksdk) || ClockPointEnum.START.getKey().equals(str.split("&")[1])){
                            newNeedClockLists.add(str.split("&")[0]+"&"+str.split("&")[1]+"&0");
                        }
                    }else if (i == lists.size()-1){
                        if (CheckBoxEnum.CHECKED.getKey().equals(evctionjsdk) || ClockPointEnum.END.getKey().equals(str.split("&")[1])){
                            newNeedClockLists.add(str.split("&")[0]+"&"+str.split("&")[1]+"&0");
                        }
                    }else {
                        newNeedClockLists.add(str.split("&")[0]+"&"+str.split("&")[1]+"&0");
                    }

                }
            }

            for (int i=0;i<scheduleResult.size();i++){
                String dtkssj = Utils.getkssjTime(scheduleResult.get(i),analysisDate);
                String dtjssj = Utils.getjssjTime(scheduleResult.get(i),analysisDate);
                for (String newNeedClock : newNeedClockLists){
                    if (ClockPointEnum.START.getKey().equals(newNeedClock.split("&")[1])){
                        if (newNeedClock.split("&")[0].equals(dtkssj)){
                            scheduleResult.get(i).put("ksdk",newNeedClock.split("&")[2]);
                        }
                    }else if (ClockPointEnum.END.getKey().equals(newNeedClock.split("&")[1])){
                        if (newNeedClock.split("&")[0].equals(dtjssj)){
                            scheduleResult.get(i).put("jsdk",newNeedClock.split("&")[2]);
                        }
                    }
                }

            }
        }
        if (askForLeaveAndEvctionScheduleList.size() > 0){


            scheduleResult.addAll(askForLeaveAndEvctionScheduleList);
            scheduleResult = scheduleResult.stream().sorted(Comparator.comparing(e->DateUtil.getTime(Utils.getkssjTime(e,analysisDate)).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());
        }

        List<String> needClockDateList = Lists.newArrayList();
        for (int i=0;i<scheduleResult.size();i++){
            String dtkssj = Utils.getkssjTime(scheduleResult.get(i),analysisDate);
            String dtjssj = Utils.getjssjTime(scheduleResult.get(i),analysisDate);

            if (CheckBoxEnum.CHECKED.getKey().equals(scheduleResult.get(i).get("ksdk"))) {
                needClockDateList.add(dtkssj);
            }
            if (CheckBoxEnum.CHECKED.getKey().equals(scheduleResult.get(i).get("jsdk"))){
                needClockDateList.add(dtjssj);
            }
        }

        /**
         * 当请假时间或出差时间包含最早上班时间和最晚下班时间时,补偿机制
         */
        if (needClockDateList.size() == 1){
            for (int i=0;i<scheduleResult.size();i++){
                String dtkssj =  Utils.getkssjTime(scheduleResult.get(i),analysisDate);
                String dtjssj = Utils.getjssjTime(scheduleResult.get(i),analysisDate);
                String bdlx = Util.null2String(scheduleResult.get(i).get("bdlx"));
                if (ifStartNeedClock && DateUtil.getTime(startNeedClockTime).compareTo(DateUtil.getTime(dtkssj)) >=0 &&
                        DateUtil.getTime(startNeedClockTime).compareTo(DateUtil.getTime(dtjssj)) <0 &&
                        !ClassSegmentTypeEnum.EVECTION.getKey().equals(bdlx) &&
                        !ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey().equals(bdlx)){
                    String firstKssj = Utils.getkssjTime(scheduleResult.get(0),analysisDate);
                    String kssj = Utils.getkssjTime(scheduleResult.get(i),analysisDate);
                    scheduleResult.get(i).put("ksdk",CheckBoxEnum.CHECKED.getKey());
                    scheduleResult.get(i).put("tqdkfzs",DateUtil.getBetWeenMinutes(firstKssj,kssj));
                    needClockDateList.add(0,dtkssj);
                    break;
                }
                if (ifEndNeedClock && DateUtil.getTime(endNeedClockTime).compareTo(DateUtil.getTime(dtkssj)) >0 &&
                        DateUtil.getTime(endNeedClockTime).compareTo(DateUtil.getTime(dtjssj)) <=0 &&
                        !ClassSegmentTypeEnum.EVECTION.getKey().equals(bdlx) &&
                        !ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey().equals(bdlx)){
                    String lastjssj = Utils.getjssjTime(scheduleResult.get(scheduleResult.size()-1),analysisDate);
                    String jssj = Utils.getjssjTime(scheduleResult.get(i),analysisDate);
                    scheduleResult.get(i).put("jsdk",CheckBoxEnum.CHECKED.getKey());
                    scheduleResult.get(i).put("thdkfzs",DateUtil.getBetWeenMinutes(jssj,lastjssj));
                    needClockDateList.add(dtjssj);
                    break;
                }
            }
        }

        needClockDateList = needClockDateList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(e).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());


        this.needClockDateList=needClockDateList;
        log.debug("经过重新计算卡点时 新的scheduleResult : [{}]",scheduleResult);



        List<ClockPointDTO> clcokInPointList = getClockInPoint(analysisDate, scheduleResult, clockInTimeList,needClockDateList);


        log.debug("clcokInPointList :[{}]",clcokInPointList);
        resultMap.put("clcokInPointList", clcokInPointList);
        resultMap.put("scheduleResult",scheduleResult);
        resultMap.put("clockInTimeList",clockInTimeList);
        resultMap.put("needClockDateList",needClockDateList);
        resultMap.put("askForLeaveAndEvctionScheduleList",askForLeaveAndEvctionScheduleList);
        return resultMap;
    }

    /**
     * 获取打卡卡点
     *
     * @param analysisDate        分析日期
     * @param scheduleResult 需要打卡的班次
     * @param clockInTimeList     打卡集合
     * @param needClockDateList     需要打卡的时间点
     * @return clcokInTimeData 卡点集合
     */
    public  List<ClockPointDTO> getClockInPoint(String analysisDate, List<Map<String, Object>> scheduleResult, List<Map<String, Object>> clockInTimeList, List<String> needClockDateList) {

        /**卡点集合*/
        List<ClockPointDTO> clcokInTimeData = Lists.newArrayList();
        List<Map<String, Object>> clockInTimeListTemp = new ArrayList<>();

        for (Map<String, Object> needClockIn : scheduleResult) {
            /**非请假外出开始打卡逻辑处理*/
            if (CheckBoxEnum.CHECKED.getKey().equals(needClockIn.get("ksdk")) && !ClassSegmentTypeEnum.EVECTION.getKey().equals(needClockIn.get("bdlx")) &&
                    !ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey().equals(needClockIn.get("bdlx"))) {
                String dtkssj = Utils.getkssjTime(needClockIn,analysisDate);
                Map<ClockPointEnum, Map<String, Object>> ksdkNearestClcokInTime = Utils.getNearestClcokInTimeCmd(dtkssj, clockInTimeList);
                ClockPointEnum timeType = getStartClassTimeType(needClockIn,ksdkNearestClcokInTime,dtkssj,dtkssj);
                clockInTimeListTemp.add(ksdkNearestClcokInTime.get(timeType));
                clcokInTimeData.add(ClockPointDTO.builder().classTime(dtkssj).pointType(ClockPointEnum.START).timeType(timeType).record(true).classSegmentType(needClockIn.get("bdlx").toString()).clockTime(ksdkNearestClcokInTime.get(timeType)).build());
            }
            /**非请假外出结束打卡逻辑处理*/
            if (CheckBoxEnum.CHECKED.getKey().equals(needClockIn.get("jsdk")) && !ClassSegmentTypeEnum.EVECTION.getKey().equals(needClockIn.get("bdlx")) &&
                    !ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey().equals(needClockIn.get("bdlx"))) {
                String dtjssj = Utils.getjssjTime(needClockIn,analysisDate);
                Map<ClockPointEnum, Map<String, Object>> jsdkNearestClcokInTime = Utils.getNearestClcokInTimeCmd(dtjssj, clockInTimeList);
                ClockPointEnum timeType = getEndClassTimeType(needClockIn,jsdkNearestClcokInTime,dtjssj,dtjssj);
                clockInTimeListTemp.add(jsdkNearestClcokInTime.get(timeType));
                clcokInTimeData.add(ClockPointDTO.builder().classTime(dtjssj).pointType(ClockPointEnum.END).timeType(timeType).record(true).classSegmentType(needClockIn.get("bdlx").toString()).clockTime(jsdkNearestClcokInTime.get(timeType)).build());
            }

            /**
             * 请假外出的开始打卡处理
             */
            if (CheckBoxEnum.CHECKED.getKey().equals(needClockIn.get("ksdk")) && (ClassSegmentTypeEnum.EVECTION.getKey().equals(needClockIn.get("bdlx")) ||
                    ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey().equals(needClockIn.get("bdlx")))){
                String dtkssj = Utils.getkssjTime(needClockIn,analysisDate);
                Map<ClockPointEnum, Map<String, Object>> jsdkNearestClcokInTime = Utils.getNearestClcokInTimeCmd(dtkssj, clockInTimeList);
                ClockPointEnum timeType = getEndClassTimeType(needClockIn,jsdkNearestClcokInTime,dtkssj,dtkssj);
                clockInTimeListTemp.add(jsdkNearestClcokInTime.get(timeType));
                clcokInTimeData.add(ClockPointDTO.builder().classTime(dtkssj).pointType(ClockPointEnum.END).record(true).timeType(timeType).classSegmentType(needClockIn.get("bdlx").toString()).clockTime(jsdkNearestClcokInTime.get(timeType)).build());
            }
            /**
             * 请假外出的结束打卡处理
             */
            if (CheckBoxEnum.CHECKED.getKey().equals(needClockIn.get("jsdk")) && (ClassSegmentTypeEnum.EVECTION.getKey().equals(needClockIn.get("bdlx")) ||
                    ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey().equals(needClockIn.get("bdlx")))){
                String dtjssj = Utils.getjssjTime(needClockIn,analysisDate);
                Map<ClockPointEnum, Map<String, Object>> ksdkNearestClcokInTime = Utils.getNearestClcokInTimeCmd(dtjssj, clockInTimeList);
                ClockPointEnum timeType = getStartClassTimeType(needClockIn,ksdkNearestClcokInTime,dtjssj,dtjssj);
                clockInTimeListTemp.add(ksdkNearestClcokInTime.get(timeType));
                clcokInTimeData.add(ClockPointDTO.builder().classTime(dtjssj).pointType(ClockPointEnum.START).record(true).timeType(timeType).classSegmentType(needClockIn.get("bdlx").toString()).clockTime(ksdkNearestClcokInTime.get(timeType)).build());
            }
        }

        //根据班次时间排序
        clcokInTimeData = clcokInTimeData.stream().sorted(Comparator.comparing(e-> DateUtil.getTime(e.getClassTime()).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());
        /**
         * 计算弹性上下班
         */  //上下班弹性，
        flexibleWork(clcokInTimeData,scheduleResult);
        /**
         * 计算休息时间段的弹性上下班
         */
        List<Map<String, Object>> restScheduleList = scheduleResult.stream().filter(e -> (ClassSegmentTypeEnum.REST_AND_DINE.getKey().equals(e.get("bdlx")) || ClassSegmentTypeEnum.REST_PERIOD.getKey().equals(e.get("bdlx"))
                || ClassSegmentTypeEnum.DINING_PERIOD.getKey().equals(e.get("bdlx"))) && CheckBoxEnum.CHECKED.getKey().equals(e.get("dtsfdx"))).collect(Collectors.toList());
        if (restScheduleList.size() > 0){
            flexibleRestClass(restScheduleList,clcokInTimeData,scheduleResult);
        }
        /**
         * 当有2笔需要打卡时，可能会有打卡歧义的情况，歧义情况取2个时间点的中间值，当打卡时间小于中间值归属前一个打卡，大于则相反
         */
        if (clcokInTimeData.size() > 1) {
            for (int i = 0; i < clcokInTimeData.size() - 1; i++) {
                ClockPointDTO beforeClcokDTO = clcokInTimeData.get(i);
                ClockPointDTO afterClcokInDTO = clcokInTimeData.get(i + 1);
                Map<String, Object> beforeClcokInTimeMap = beforeClcokDTO.getClockTime();
                Map<String, Object> afterClcokInTimeMap = afterClcokInDTO.getClockTime();

                //重复
                if (beforeClcokInTimeMap != null && beforeClcokInTimeMap == afterClcokInTimeMap) {
                    String beforeTime = beforeClcokDTO.getClassTime();
                    if (beforeClcokDTO.getElasticTime() != null && !"".equals(beforeClcokDTO.getElasticTime())){
                        beforeTime = beforeClcokDTO.getElasticTime();
                    }
                    String afterTime = afterClcokInDTO.getClassTime();
                    if (afterClcokInDTO.getElasticTime() != null && !"".equals(afterClcokInDTO.getElasticTime())){
                        afterTime = afterClcokInDTO.getElasticTime();
                    }
                    long betWeenMinutes = DateUtil.getBetWeenMinutes(beforeTime, afterTime);

                    String middileTime = DateUtil.AfterMinutes(beforeTime, betWeenMinutes / 2);

                    String signdateTime = beforeClcokInTimeMap.get("signdate") + " " + beforeClcokInTimeMap.get("signtime");

                    ClockPointDTO resetClcokDTO =null;
                    if (DateUtil.getTime(signdateTime).compareTo(DateUtil.getTime(middileTime)) <= 0) {
                        //该打卡归属前一个打卡点，后一个打卡点需要重新设置
                        resetClcokDTO=afterClcokInDTO;
                    } else if (DateUtil.getTime(signdateTime).compareTo(DateUtil.getTime(middileTime)) > 0) {
                        //该打卡归属后一个打卡点，前一个打卡点需要重新设置
                        resetClcokDTO=beforeClcokDTO;
                    }

                    //需要重新赋值的打卡时间
                    String restTime = resetClcokDTO.getClassTime();
                    if (resetClcokDTO.getElasticTime() != null && !"".equals(resetClcokDTO.getElasticTime())){
                        restTime = resetClcokDTO.getElasticTime();
                    }
                    Map<ClockPointEnum, Map<String, Object>> nearestClcokInTime = Utils.getNearestClcokInTimeCmd(restTime, clockInTimeList);
                    //start：开始打卡时间点，end：结束打卡时间点
                    ClockPointEnum pointType = resetClcokDTO.getPointType();
                    //empty:漏卡，equal:打卡时间和班次时间相等，before：打卡时间在班次时间之前，after：打卡时间在班次时间之后
                    ClockPointEnum timeType = resetClcokDTO.getTimeType();
                    String time = resetClcokDTO.getClassTime();

                    ClockPointEnum newtimeType = null;
                    if (timeType.equals(ClockPointEnum.BEFORE)){
                        newtimeType = ClockPointEnum.AFTER;
                    }else if (timeType.equals(ClockPointEnum.AFTER)){
                        newtimeType = ClockPointEnum.BEFORE;
                    }
                    if (nearestClcokInTime.get(newtimeType) != null){
                        Map<String, Object> newClockTimeMap = nearestClcokInTime.get(newtimeType);
                        String newClockTime = newClockTimeMap.get("signdate")+ " "+newClockTimeMap.get("signtime");
                        int index = clcokInTimeData.indexOf(resetClcokDTO);
                        if (newtimeType.equals(ClockPointEnum.BEFORE)){
                            if (!getBeforeClockTime(needClockDateList, restTime).equals("") && DateUtil.getTime(newClockTime).compareTo(DateUtil.getTime(getBeforeClockTime(needClockDateList, restTime))) <= 0){
                                newClockTimeMap = null;
                            }

                            if ((index-1) >= 0){
                                //当重新需要打卡的时间戳与打卡时间之前的打卡集合时，进行比对
                                ClockPointDTO resetBeforeDTO =  clcokInTimeData.get(index-1);
                                Map<String, Object> resetBeforeClcokInTimeMap = resetBeforeDTO.getClockTime();
                                if (newClockTimeMap == resetBeforeClcokInTimeMap){
                                    newClockTimeMap = null;
                                }
                            }
                        }else if (newtimeType.equals(ClockPointEnum.AFTER)){
                            if (!getNextClockTime(needClockDateList,restTime).equals("") && DateUtil.getTime(newClockTime).compareTo(DateUtil.getTime(getNextClockTime(needClockDateList,restTime))) >= 0){
                                newClockTimeMap = null;
                            }
                        }
                        if (newClockTimeMap == null){
                            //当需要调整的卡点为漏卡时将打卡进行退回，若另一个卡点调整后为不漏卡情况，则调整该节点
                            if (resetClcokDTO == beforeClcokDTO){
                                resetClcokDTO=afterClcokInDTO;
                            }else if (resetClcokDTO == afterClcokInDTO){
                                resetClcokDTO=beforeClcokDTO;
                            }
                            if (!resetClcokInTimeData(analysisDate,resetClcokDTO,clockInTimeList,needClockDateList,clcokInTimeData,scheduleResult)){
                                if (resetClcokDTO == beforeClcokDTO){
                                    resetClcokDTO = afterClcokInDTO;
                                }else if (resetClcokDTO == afterClcokInDTO){
                                    resetClcokDTO = beforeClcokDTO;
                                }

                                if (newClockTimeMap == null){
                                    resetClcokDTO.setTimeType(ClockPointEnum.EMPTY);
                                }else {
                                    resetClcokDTO.setTimeType(newtimeType);
                                }
                                resetClcokDTO.setClockTime(newClockTimeMap);
                            }
                        }else {
                            if (newClockTimeMap == null){
                                resetClcokDTO.setTimeType(ClockPointEnum.EMPTY);
                            }else {
                                resetClcokDTO.setTimeType(newtimeType);
                            }
                            resetClcokDTO.setClockTime(newClockTimeMap);
                        }
                    }else {
                        if (resetClcokDTO == beforeClcokDTO){
                            resetClcokDTO = afterClcokInDTO;
                        }else if (resetClcokDTO == afterClcokInDTO){
                            resetClcokDTO = beforeClcokDTO;
                        }
                        if (!resetClcokInTimeData(analysisDate,resetClcokDTO,clockInTimeList,needClockDateList,clcokInTimeData,scheduleResult)){
                            if (resetClcokDTO == beforeClcokDTO){
                                resetClcokDTO = afterClcokInDTO;
                            }else if (resetClcokDTO == afterClcokInDTO){
                                resetClcokDTO = beforeClcokDTO;
                            }
                            resetClcokDTO.setClockTime(null);
                            resetClcokDTO.setTimeType(ClockPointEnum.EMPTY);
                        }
                    }
                }
            }
        }

        return clcokInTimeData;
    }




    public boolean resetClcokInTimeData(String analysisDate,ClockPointDTO resetClcokDTO,List<Map<String, Object>> clockInTimeList, List<String> needClockDateList,List<ClockPointDTO> clcokInTimeData,List<Map<String, Object>> scheduleResult){
        String restTime = resetClcokDTO.getClassTime();
        if (resetClcokDTO.getElasticTime() != null && !"".equals(resetClcokDTO.getElasticTime())){
            restTime = resetClcokDTO.getElasticTime();
        }
        Map<ClockPointEnum, Map<String, Object>> nearestClcokInTime = Utils.getNearestClcokInTimeCmd(restTime, clockInTimeList);
        //start：开始打卡时间点，end：结束打卡时间点
        ClockPointEnum pointType = resetClcokDTO.getPointType();
        //empty:漏卡，equal:打卡时间和班次时间相等，before：打卡时间在班次时间之前，after：打卡时间在班次时间之后
        ClockPointEnum timeType = resetClcokDTO.getTimeType();
        String time = resetClcokDTO.getClassTime();

        ClockPointEnum newtimeType = null;
        if (timeType.equals(ClockPointEnum.BEFORE)){
            newtimeType = ClockPointEnum.AFTER;
        }else if (timeType.equals(ClockPointEnum.AFTER)){
            newtimeType = ClockPointEnum.BEFORE;
        }

        if (nearestClcokInTime.get(newtimeType) != null){

            Map<String, Object> newClockTimeMap = nearestClcokInTime.get(newtimeType);
            String newClockTime = newClockTimeMap.get("signdate")+ " "+newClockTimeMap.get("signtime");
            int index = clcokInTimeData.indexOf(resetClcokDTO);
            if (newtimeType.equals(ClockPointEnum.BEFORE)){
                if (pointType.equals(ClockPointEnum.START)){
                    //开始卡点
                    Map<String,Object> needClockIn = scheduleResult.stream().filter(e -> {
                        String dtkssj = Utils.getkssjTime(e,analysisDate);
                        if (Utils.ifAskforOrEvctionClassSegment(e.get("bdlx").toString())){
                            dtkssj = Utils.getjssjTime(e,analysisDate);
                        }
                        if (time.equals(dtkssj)){
                            return true;
                        }else {
                            return  false;
                        }
                    }).collect(Collectors.toList()).get(0);
                    //计算最大提前打卡分钟数
                    int tqdkfzs = 60;
                    if (Util.null2String(needClockIn.get("tqdkfzs")).equals("") && !"".equals(getBeforeClockTime(needClockDateList,restTime))){
                        tqdkfzs = DateUtil.getBetWeenMinutes(getBeforeClockTime(needClockDateList,restTime),restTime);
                    }else {
                        tqdkfzs = Util.null2String(needClockIn.get("tqdkfzs")).equals("")?60:Integer.valueOf(needClockIn.get("tqdkfzs").toString());
                    }
                    if (DateUtil.getTime(newClockTime).compareTo(DateUtil.getTime(DateUtil.beforeMinutes(restTime, tqdkfzs))) < 0){
                        newClockTimeMap =null;
                    }

                }
                if (!getBeforeClockTime(needClockDateList,restTime).equals("") && DateUtil.getTime(newClockTime).compareTo(DateUtil.getTime(getBeforeClockTime(needClockDateList,restTime))) <= 0){
                    newClockTimeMap = null;
                }

                if ((index-1) >= 0){
                    //当重新需要打卡的时间戳与打卡时间之前的打卡集合时，进行比对
                    ClockPointDTO resetBeforeDTO =  clcokInTimeData.get(index-1);
                    Map<String, Object> resetBeforeClcokInTimeMap = resetBeforeDTO.getClockTime();
                    if (newClockTimeMap == resetBeforeClcokInTimeMap){
                        newClockTimeMap = null;
                    }
                }
            }else if (newtimeType.equals(ClockPointEnum.AFTER)){
                if (pointType.equals(ClockPointEnum.END)){
                    //结束卡点
                    Map<String,Object> needClockIn = scheduleResult.stream().filter(e -> {
                        String dtjssj = Utils.getjssjTime(e,analysisDate);
                        if (Utils.ifAskforOrEvctionClassSegment(e.get("bdlx").toString())){
                            dtjssj = Utils.getkssjTime(e,analysisDate);
                        }
                        if (time.equals(dtjssj)){
                            return true;
                        }else {
                            return  false;
                        }
                    }).collect(Collectors.toList()).get(0);
                    //计算最大退后打卡分钟数
                    int thdkfzs = 60;
                    if (Util.null2String(needClockIn.get("thdkfzs")).equals("") && !"".equals(getNextClockTime(needClockDateList,restTime))){
                        thdkfzs = DateUtil.getBetWeenMinutes(restTime,getNextClockTime(needClockDateList,restTime));
                    }else {
                        thdkfzs = Util.null2String(needClockIn.get("thdkfzs")).equals("")?60:Integer.valueOf(needClockIn.get("thdkfzs").toString());
                    }
                    if (DateUtil.getTime(newClockTime).compareTo(DateUtil.getTime(DateUtil.AfterMinutes(restTime, thdkfzs))) > 0){
                        newClockTimeMap = null;
                    }
                }
                if (!getNextClockTime(needClockDateList,restTime).equals("") && DateUtil.getTime(newClockTime).compareTo(DateUtil.getTime(getNextClockTime(needClockDateList,restTime))) >= 0){
                    newClockTimeMap = null;
                }
            }
            if (newClockTimeMap != null){
                resetClcokDTO.setTimeType(newtimeType);
                resetClcokDTO.setClockTime(newClockTimeMap);
                return true;
            }
        }
        return false;
    }

    /**
     * 连续两上上班段（正常工作、班段上加班、加班计划）如果上一个结束与下一个开始都需要打卡，则两个都调整来不需要打卡
     * @param scheduleResult
     * @return
     */
    public List<Map<String, Object>> adjustWorkOverTimeClock(List<Map<String, Object>> scheduleResult,String analysisDate){
        List<Map<String, Object>> workscheduleList = scheduleResult.stream().filter(e->!Utils.ifRestClassSegment(e.get("bdlx").toString())).collect(Collectors.toList());
        List<Map<String, Object>> restscheduleList = scheduleResult.stream().filter(e->Utils.ifRestClassSegment(e.get("bdlx").toString())).collect(Collectors.toList());

        workscheduleList = workscheduleList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(Utils.getkssjTime(e,analysisDate)).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());
        for (int i=0;i<workscheduleList.size();i++){
            Map<String, Object> scheduleMap = workscheduleList.get(i);
            if (scheduleMap.get("bdlx").equals(ClassSegmentTypeEnum.OVERTIME_PLAN.getKey())){
                String kssj = Utils.getkssjTime(scheduleMap,analysisDate);
                String jssj = Utils.getjssjTime(scheduleMap,analysisDate);
                Map<String, Object> beforeScheduleMap = i-1 >=0?workscheduleList.get(i-1):null;
                Map<String, Object> afterScheduleMap = i+1 <=workscheduleList.size()-1?workscheduleList.get(i+1):null;
                if (beforeScheduleMap != null && afterScheduleMap != null && ifWorkClassSegment(beforeScheduleMap.get("bdlx").toString()) &&
                        ifWorkClassSegment(afterScheduleMap.get("bdlx").toString())){
                    //加班计划处在工作中间，休息时段加班
                    String beforejssj = Utils.getjssjTime(beforeScheduleMap,analysisDate);
                    String afterkssj = Utils.getkssjTime(afterScheduleMap,analysisDate);
                    if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(beforejssj)) == 0){
                        beforeScheduleMap.put("jsdk",CheckBoxEnum.UNCHECKED.getKey());
                        scheduleMap.put("ksdk",CheckBoxEnum.UNCHECKED.getKey());
                        beforeScheduleMap.put("jsdk",CheckBoxEnum.UNCHECKED.getKey());
                    }
                    if (DateUtil.getTime(jssj).compareTo(DateUtil.getTime(afterkssj)) == 0){
                        scheduleMap.put("jsdk",CheckBoxEnum.UNCHECKED.getKey());
                        afterScheduleMap.put("ksdk",CheckBoxEnum.UNCHECKED.getKey());
                    }

                }else {
                    if (beforeScheduleMap != null){
                        String beforejssj = Utils.getjssjTime(beforeScheduleMap,analysisDate);
                        if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(beforejssj)) == 0 && ifWorkClassSegment(beforeScheduleMap.get("bdlx").toString()) &&
                                scheduleMap.get("jsdk").equals(CheckBoxEnum.CHECKED.getKey())){
                            scheduleMap.put("ksdk",CheckBoxEnum.UNCHECKED.getKey());
                            beforeScheduleMap.put("jsdk",CheckBoxEnum.UNCHECKED.getKey());
                        }
                        if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(beforejssj)) == 0 && ifWorkClassSegment(beforeScheduleMap.get("bdlx").toString()) &&
                                scheduleMap.get("jsdk").equals(CheckBoxEnum.UNCHECKED.getKey()) &&  scheduleMap.get("ksdk").equals(CheckBoxEnum.CHECKED.getKey()) &&
                                beforeScheduleMap.get("jsdk").equals(CheckBoxEnum.CHECKED.getKey())){
                            scheduleMap.put("ksdk",CheckBoxEnum.UNCHECKED.getKey());
                        }

                    }
                    if (afterScheduleMap != null){
                        String afterkssj = Utils.getkssjTime(afterScheduleMap,analysisDate);
                        if (DateUtil.getTime(jssj).compareTo(DateUtil.getTime(afterkssj)) == 0 && ifWorkClassSegment(afterScheduleMap.get("bdlx").toString()) &&
                                scheduleMap.get("ksdk").equals(CheckBoxEnum.CHECKED.getKey())){
                            scheduleMap.put("jsdk",CheckBoxEnum.UNCHECKED.getKey());
                            afterScheduleMap.put("ksdk",CheckBoxEnum.UNCHECKED.getKey());
                        }

                        if (DateUtil.getTime(jssj).compareTo(DateUtil.getTime(afterkssj)) == 0 && ifWorkClassSegment(afterScheduleMap.get("bdlx").toString()) &&
                                scheduleMap.get("ksdk").equals(CheckBoxEnum.UNCHECKED.getKey()) &&scheduleMap.get("jsdk").equals(CheckBoxEnum.CHECKED.getKey()) &&
                                afterScheduleMap.get("ksdk").equals(CheckBoxEnum.CHECKED.getKey())){
                            scheduleMap.put("jsdk",CheckBoxEnum.UNCHECKED.getKey());
                        }
                    }
                }
            }
        }
        List<Map<String, Object>> newList = Lists.newArrayList();
        newList.addAll(workscheduleList);
        newList.addAll(restscheduleList);
        newList = newList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(Utils.getkssjTime(e,analysisDate)).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());


        return newList;
    }

    /**
     * 请假出差碰到休息时段时调整打卡
     * @param scheduleResult
     * @param analysisDate
     * @param askForLeaveAndEvctionScheduleList
     * @return
     */
    public List<Map<String, Object>> adjustAskforSchedule(List<Map<String, Object>> scheduleResult,String analysisDate,List<Map<String, Object>> askForLeaveAndEvctionScheduleList){
        List<Map<String, Object>> restscheduleList = scheduleResult.stream().filter(e->Utils.ifRestClassSegment(e.get("bdlx").toString())).collect(Collectors.toList());
        List<Map<String, Object>> newList = Lists.newArrayList();
        if (askForLeaveAndEvctionScheduleList.size()>1){
            askForLeaveAndEvctionScheduleList = askForLeaveAndEvctionScheduleList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(Utils.getkssjTime(e,analysisDate)).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());

            for (int i = 0; i < askForLeaveAndEvctionScheduleList.size() - 1; i++) {
                String beforeDtkssj = Utils.getkssjTime(askForLeaveAndEvctionScheduleList.get(i),analysisDate);
                String beforeDtjssj = Utils.getjssjTime(askForLeaveAndEvctionScheduleList.get(i),analysisDate);

                String afterDtkssj = Utils.getkssjTime(askForLeaveAndEvctionScheduleList.get(i+1),analysisDate);
                String afterDtjssj= Utils.getkssjTime(askForLeaveAndEvctionScheduleList.get(i+1),analysisDate);

                List<Map<String, Object>> occupyRestSchedule = restscheduleList.stream().filter(e->DateUtil.getTime(Utils.getkssjTime(e,analysisDate)).compareTo(DateUtil.getTime(beforeDtjssj))<=0 &&
                        DateUtil.getTime(Utils.getjssjTime(e,analysisDate)).compareTo(DateUtil.getTime(beforeDtjssj)) >= 0).collect(Collectors.toList());
                if (occupyRestSchedule.size() > 0 && DateUtil.getTime(Utils.getjssjTime(occupyRestSchedule.get(0),analysisDate)).compareTo(DateUtil.getTime(afterDtkssj)) >=0){
                    askForLeaveAndEvctionScheduleList.get(i).put("jsdk",CheckBoxEnum.UNCHECKED.getKey());
                    askForLeaveAndEvctionScheduleList.get(i+1).put("ksdk",CheckBoxEnum.UNCHECKED.getKey());
                }
            }
            newList=askForLeaveAndEvctionScheduleList;
        }else {
            newList = askForLeaveAndEvctionScheduleList;
        }

        return newList;
    }

    /**
     * 早晚上下班弹性
     */
    public void flexibleWork(List<ClockPointDTO> clcokInTimeData,List<Map<String, Object>> scheduleResult){
        List<Map<String, Object>> clockInTimeList = (List<Map<String, Object>>) params.get("clockInTimeList");
        List<Map<String, Object>> workScheduleList = scheduleResult.stream().filter(e -> ClassSegmentTypeEnum.WORK_TIME.getKey().equals(e.get("bdlx")) || ClassSegmentTypeEnum.EARLY_OVERTIME.getKey().equals(e.get("bdlx"))).collect(Collectors.toList());
        if (scheduleResult.size() > 0 && workScheduleList.size()>0) {

            //请假和外出集合
            List<Map<String, Object>> leaveAndEvctionList = scheduleResult.stream().filter(e -> ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey().equals(e.get("bdlx")) ||
                    ClassSegmentTypeEnum.EVECTION.getKey().equals(e.get("bdlx"))).collect(Collectors.toList());
            //是否弹性
            String sfdx = Util.null2String(workScheduleList.get(0).get("sfdx"));
            //上班是否需要打卡
            String ifToWorkClock = Util.null2String(workScheduleList.get(0).get("ksdk"));
            //下班是否需要打卡
            String ifToCloseClock = Util.null2String(workScheduleList.get(workScheduleList.size()-1).get("jsdk"));

            //第一条工作时段、早上加班
            if (workScheduleList.size() > 0 && CheckBoxEnum.CHECKED.getKey().equals(sfdx)) {
                //最大弹性分钟
                int zddxfz = Integer.valueOf(Util.null2String(workScheduleList.get(0).get("zddxfz")));
                //弹性核算
                int dxhs = Integer.valueOf(Util.null2String(workScheduleList.get(0).get("dxhs")));
                Map<String, Object> ksdkMap = workScheduleList.get(0);
                //最早上班时间
                String kssjStart = Utils.getkssjTime(ksdkMap,analysisDate);


                Map<String, Object> jsdkMap = workScheduleList.get(workScheduleList.size() - 1);
                //最晚下班时间
                int thdkfzs = Integer.valueOf(Util.null2String(jsdkMap.get("thdkfzs")).equals("")?"60":Util.null2String(jsdkMap.get("thdkfzs")));
                String jssjEnd = Utils.getjssjTime(jsdkMap,analysisDate);


                //弹性上班时间
                String flexibleWorkTime = "";
                //弹性下班时间
                String flexibleOffWorkTime="";
                if (leaveAndEvctionList.size() >0){
                    //第一笔请假、外出时间
                    Map<String, Object> leaveAndEvctionMap = leaveAndEvctionList.get(0);
                    String leaveAndEvctionkssj = Utils.getkssjTime(leaveAndEvctionMap,analysisDate);
                    //最大开始弹性时间
                    String minkssjStart = DateUtil.beforeMinutes(kssjStart,zddxfz);
                    String maxkssjStart = DateUtil.AfterMinutes(kssjStart,zddxfz);
                    //请假开始时间在最大开始弹性时间之内
                    if (DateUtil.getTime(leaveAndEvctionkssj).compareTo(DateUtil.getTime(maxkssjStart))<=0){
                        //弹性上班卡
                        flexibleWorkTime = leaveAndEvctionkssj;
                        if (DateUtil.getTime(leaveAndEvctionkssj).compareTo(DateUtil.getTime(minkssjStart)) <0){
                            flexibleWorkTime=minkssjStart;
                        }

                        //弹性下班时间点
                        int betweenToWorkTime = DateUtil.getBetWeenMinutes(flexibleWorkTime, kssjStart);
                        //弹性下班时间点
                        flexibleOffWorkTime = jssjEnd;
                        if (betweenToWorkTime >= 0) {
                            flexibleOffWorkTime = DateUtil.beforeMinutes(flexibleOffWorkTime, Math.abs(betweenToWorkTime));
                        } else if (betweenToWorkTime < 0) {
                            flexibleOffWorkTime = DateUtil.AfterMinutes(flexibleOffWorkTime, Math.abs(betweenToWorkTime));
                        }

                    }
                }
                //弹性上班卡
                for (int i = 0; i < clcokInTimeData.size(); i++) {
                    ClockPointDTO clockdto = clcokInTimeData.get(i);

                    //需要计算的班次打卡时间点
                    String pointTime = clockdto.getClassTime();
                    //start：开始打卡时间点，end：结束打卡时间点
                    ClockPointEnum pointType = clockdto.getPointType();

                    //重新获取最早上班时间
                    Map<ClockPointEnum, Map<String, Object>> startNearestClcokInTime = Utils.getNearestClcokInTimeCmd(DateUtil.beforeMinutes(clockdto.getClassTime(),zddxfz), clockInTimeList);
                    ClockPointEnum timeType = getStartClassTimeType(ksdkMap,startNearestClcokInTime,kssjStart,DateUtil.beforeMinutes(kssjStart,zddxfz));
                    clockdto.setTimeType(timeType);
                    clockdto.setClockTime(startNearestClcokInTime.get(timeType));

                    Map<String, Object> clcokInTime = clockdto.getClockTime();

                    if (pointTime.equals(kssjStart) && ClockPointEnum.START.equals(pointType) && clcokInTime != null
                            && CheckBoxEnum.CHECKED.getKey().equals(ifToWorkClock)) {
                        //该卡点是弹性开始时间
                        //弹性上班期间未被请假开始时间占据
                        if ("".equals(flexibleWorkTime) ){
                            String signTime = clcokInTime.get("signdate") + " " + clcokInTime.get("signtime");
                            if (ClockPointEnum.BEFORE.equals(timeType)) {
                                int betWeenTime = DateUtil.getBetWeenMinutes(signTime, kssjStart);
                                if (betWeenTime <= zddxfz) {
                                    betWeenTime = Double.valueOf(Utils.getItemdurationDown(dxhs, AccountingUnitEnum.MINUTES.getKey(), betWeenTime, AccountingUnitEnum.MINUTES)).intValue();
                                    flexibleWorkTime = DateUtil.beforeMinutes(kssjStart, betWeenTime);
                                    clockdto.setTimeType(ClockPointEnum.EQUAL);
                                } else if (betWeenTime > zddxfz) {
                                    flexibleWorkTime = DateUtil.beforeMinutes(kssjStart, zddxfz);
                                }
                                clockdto.setElasticTime(flexibleWorkTime);
                            } else if (ClockPointEnum.AFTER.equals(timeType)) {
                                //迟到
                                int betWeenTime = DateUtil.getBetWeenMinutes(kssjStart, signTime);
                                if (betWeenTime <= zddxfz) {
                                    betWeenTime = Double.valueOf(Utils.getItemduration(dxhs, AccountingUnitEnum.MINUTES.getKey(), betWeenTime, AccountingUnitEnum.MINUTES,Double.valueOf(scheduleResult.get(0).get("edsc").toString()))).intValue();
                                    flexibleWorkTime = DateUtil.AfterMinutes(kssjStart, betWeenTime);
                                    clockdto.setTimeType(ClockPointEnum.EQUAL);
                                } else if (betWeenTime > zddxfz) {
                                    flexibleWorkTime = DateUtil.AfterMinutes(kssjStart, zddxfz);
                                }
                                clockdto.setElasticTime(flexibleWorkTime);
                            }
                        }else {
                            //弹性上班期间被请假开始时间占据
                            clockdto.setElasticTime(flexibleWorkTime);
                        }
                        //重新设置打卡时间
                        int startWorkIndex = needClockDateList.indexOf(kssjStart);
                        needClockDateList.remove(startWorkIndex);
                        needClockDateList.add(startWorkIndex,clockdto.getElasticTime());
                    } else if (pointTime.equals(jssjEnd) && ClockPointEnum.END.equals(pointType) && CheckBoxEnum.CHECKED.getKey().equals(ifToCloseClock)) {
                        //该卡点是弹性下班点
                        if ("".equals(flexibleOffWorkTime) && !"".equals(flexibleWorkTime)){
                            int betweenToWorkTime = DateUtil.getBetWeenMinutes(flexibleWorkTime, kssjStart);
                            //弹性下班时间点
                            flexibleOffWorkTime = jssjEnd;
                            if (betweenToWorkTime >= 0) {
                                flexibleOffWorkTime = DateUtil.beforeMinutes(flexibleOffWorkTime, Math.abs(betweenToWorkTime));
                            } else if (betweenToWorkTime < 0) {
                                flexibleOffWorkTime = DateUtil.AfterMinutes(flexibleOffWorkTime, Math.abs(betweenToWorkTime));
                            }
                        }
                        if (!"".equals(flexibleOffWorkTime)){
                            //重新设置打卡时间
                            int endWorkIndex = needClockDateList.indexOf(jssjEnd);
                            needClockDateList.remove(endWorkIndex);
                            needClockDateList.add(endWorkIndex,flexibleOffWorkTime);

                            //根据弹性下班时间点重新计算
                            Map<ClockPointEnum, Map<String, Object>> jsdkNearestClcokInTime = Utils.getNearestClcokInTimeCmd(flexibleOffWorkTime, clockInTimeList);

                            ClockPointEnum newtimeType = getEndClassTimeType(jsdkMap,jsdkNearestClcokInTime,flexibleOffWorkTime,flexibleOffWorkTime);

                            clockdto.setClassTime(jssjEnd);
                            clockdto.setPointType(ClockPointEnum.END);
                            clockdto.setTimeType(newtimeType);
                            clockdto.setElasticTime(flexibleOffWorkTime);
                            clockdto.setClockTime(jsdkNearestClcokInTime.get(newtimeType));
                        }
                    }
                }
            }
        }

    }


    /**
     * 休息时段弹性
     */
    public void flexibleRestClass(List<Map<String, Object>> restScheduleList,List<ClockPointDTO> clcokInTimeData,List<Map<String, Object>> scheduleResult){
        String analysisDate = Util.null2String(params.get("analysisDate"));
        List<Map<String, Object>> clockInTimeList = (List<Map<String, Object>>) params.get("clockInTimeList");

        for (Map<String, Object> restSchedule:restScheduleList){
            String dtkssj = Utils.getkssjTime(restSchedule,analysisDate);
            String dtjssj = Utils.getjssjTime(restSchedule,analysisDate);
            //最大弹性分钟
            int dtzddxfz = Integer.valueOf(Util.null2String(restSchedule.get("dtzddxfz")));
            //弹性核算
            double dtdxhs = Utils.convertDouble(restSchedule.get("dtdxhs"));

            //下班去休息卡点
            ClockPointDTO toRestClockPointDTO = null;
            //休息完上班卡点,.
            ClockPointDTO endRestClockPointDTO = null;
            for (ClockPointDTO clockPointDTO:clcokInTimeData){

                if (clockPointDTO.getClassTime().equals(dtkssj) && clockPointDTO.getPointType()==ClockPointEnum.END){
                    toRestClockPointDTO = clockPointDTO;
                }else if (clockPointDTO.getClassTime().equals(dtjssj) && clockPointDTO.getPointType()==ClockPointEnum.START){
                    endRestClockPointDTO = clockPointDTO;
                }
            }
            List<Map<String, Object>> endRestSchedule = scheduleResult.stream().filter(e->dtjssj.equals(Utils.getkssjTime(e,analysisDate))).collect(Collectors.toList());
            List<Map<String, Object>> startRestSchedule = scheduleResult.stream().filter(e->dtkssj.equals(Utils.getjssjTime(e,analysisDate))).collect(Collectors.toList());

            /**
             * 当休息时段的开始和结束时间都要打卡时才进行弹性
             */
            if (toRestClockPointDTO != null && endRestClockPointDTO != null && toRestClockPointDTO.getClockTime() != null){

                String toRestClassTime = toRestClockPointDTO.getClassTime();
                String endRestClassTime = endRestClockPointDTO.getClassTime();
                Map<ClockPointEnum, Map<String, Object>> toRestNearestClcokInTime = Utils.getNearestClcokInTimeCmd(DateUtil.beforeMinutes(dtkssj,dtzddxfz), clockInTimeList);
                ClockPointEnum timeType = getEndClassTimeType(startRestSchedule.get(0),toRestNearestClcokInTime,dtkssj,DateUtil.AfterMinutes(dtkssj,dtzddxfz));
                toRestClockPointDTO.setTimeType(timeType);
                toRestClockPointDTO.setClockTime(toRestNearestClcokInTime.get(timeType));


                Map<String, Object> toRestClockTimeMap = toRestClockPointDTO.getClockTime();

                if (toRestClockTimeMap == null || toRestClockTimeMap.size() == 0 || toRestClockPointDTO.getTimeType() == ClockPointEnum.EQUAL || toRestClockPointDTO.getTimeType() == ClockPointEnum.EMPTY){
                    //不存在打卡时间，打卡时间与班次时间相等，漏卡
                    continue;
                }
                String toRestClockTime = toRestClockTimeMap.get("signdate")+" "+toRestClockTimeMap.get("signtime");
                int betweenMinute = 0;
                //设置下上班的弹性时间
                if (toRestClockPointDTO.getTimeType() == ClockPointEnum.BEFORE){
                    betweenMinute = DateUtil.getBetWeenMinutes(toRestClockTime,toRestClassTime);
                    if (betweenMinute > dtzddxfz){
                        toRestClockPointDTO.setElasticTime(DateUtil.beforeMinutes(toRestClassTime,dtzddxfz));
                        toRestClockPointDTO.setTimeType(ClockPointEnum.BEFORE);
                        endRestClockPointDTO.setElasticTime(DateUtil.beforeMinutes(endRestClassTime,dtzddxfz));
                    }else {
                        betweenMinute = Double.valueOf(Utils.getItemdurationDown(dtdxhs, AccountingUnitEnum.MINUTES.getKey(), betweenMinute, AccountingUnitEnum.MINUTES)).intValue();
                        endRestClockPointDTO.setElasticTime(DateUtil.beforeMinutes(endRestClassTime,betweenMinute));
                    }
                }else if (toRestClockPointDTO.getTimeType() == ClockPointEnum.AFTER){
                    betweenMinute = DateUtil.getBetWeenMinutes(toRestClassTime,toRestClockTime);
                    betweenMinute = Double.valueOf(Utils.getItemdurationDown(dtdxhs, AccountingUnitEnum.MINUTES.getKey(), betweenMinute, AccountingUnitEnum.MINUTES)).intValue();
                    endRestClockPointDTO.setElasticTime(DateUtil.AfterMinutes(endRestClassTime,betweenMinute));
                    if (betweenMinute > dtzddxfz){
                        toRestClockPointDTO.setElasticTime(DateUtil.AfterMinutes(toRestClassTime,dtzddxfz));
                        toRestClockPointDTO.setTimeType(ClockPointEnum.AFTER);
                        endRestClockPointDTO.setElasticTime(DateUtil.AfterMinutes(endRestClassTime,dtzddxfz));
                    }else {
                        betweenMinute = Double.valueOf(Utils.getItemdurationDown(dtdxhs, AccountingUnitEnum.MINUTES.getKey(), betweenMinute, AccountingUnitEnum.MINUTES)).intValue();
                        endRestClockPointDTO.setElasticTime(DateUtil.AfterMinutes(endRestClassTime,betweenMinute));
                    }
                }
                if (betweenMinute <= dtzddxfz){
                    toRestClockPointDTO.setElasticTime(toRestClockTime);
                    toRestClockPointDTO.setTimeType(ClockPointEnum.EQUAL);
                }
                //重新设置打卡时间
                int toRestIndex = needClockDateList.indexOf(toRestClockPointDTO.getClassTime());
                needClockDateList.remove(toRestIndex);
                needClockDateList.add(toRestIndex,toRestClockPointDTO.getElasticTime());

                int endRestIndex = needClockDateList.indexOf(endRestClockPointDTO.getClassTime());
                needClockDateList.remove(endRestIndex);
                needClockDateList.add(endRestIndex,endRestClockPointDTO.getElasticTime());

                //变更休息时间
                restSchedule.put("dtkssj",toRestClockPointDTO.getElasticTime().split(" ")[1]);
                restSchedule.put("dtjssj",endRestClockPointDTO.getElasticTime().split(" ")[1]);

                //根据弹性上班时间点重新获取打卡时间
                Map<ClockPointEnum, Map<String, Object>> ksdkNearestClcokInTime = Utils.getNearestClcokInTimeCmd(endRestClockPointDTO.getElasticTime(), clockInTimeList);
                ClockPointEnum endResttimeType = getStartClassTimeType(endRestSchedule.get(0),ksdkNearestClcokInTime,endRestClockPointDTO.getElasticTime(),endRestClockPointDTO.getElasticTime());
                endRestClockPointDTO.setClockTime(ksdkNearestClcokInTime.get(endResttimeType));
                endRestClockPointDTO.setTimeType(endResttimeType);

                // 休息时段的开始和结束的打卡时间一样进行还原
                Map<String, Object> endRestClockTimeMap = endRestClockPointDTO.getClockTime();
                if ((!CollectionUtils.isEmpty(endRestClockTimeMap)) && endRestClockPointDTO.getTimeType() != ClockPointEnum.EMPTY &&
                        StringUtils.equals(toRestClockPointDTO.getClockTime().get("signtime") + "", endRestClockTimeMap.get("signtime") + "")) {
                    //当弹性结束未匹配到打卡，弹性失效，进行还原

                    restSchedule.put("dtkssj",toRestClockPointDTO.getClassTime().split(" ")[1]);
                    restSchedule.put("dtjssj",endRestClockPointDTO.getClassTime().split(" ")[1]);

                    //重新设置打卡时间
                    toRestIndex = needClockDateList.indexOf(toRestClockPointDTO.getElasticTime());
                    needClockDateList.remove(toRestIndex);
                    needClockDateList.add(toRestIndex,toRestClockPointDTO.getClassTime());

                    endRestIndex = needClockDateList.indexOf(endRestClockPointDTO.getElasticTime());
                    needClockDateList.remove(endRestIndex);
                    needClockDateList.add(endRestIndex,endRestClockPointDTO.getClassTime());
                    if (toRestClockPointDTO.getClockTime() != null){
                        String time = toRestClockPointDTO.getClockTime().get("signdate")+" "+toRestClockPointDTO.getClockTime().get("signtime");
                        if (DateUtil.getTime(time).compareTo(DateUtil.getTime(toRestClockPointDTO.getClassTime())) > 0){
                            toRestClockPointDTO.setTimeType(ClockPointEnum.AFTER);
                        }else if (DateUtil.getTime(time).compareTo(DateUtil.getTime(toRestClockPointDTO.getClassTime())) ==0){
                            toRestClockPointDTO.setTimeType(ClockPointEnum.EQUAL);
                        }else {
                            toRestClockPointDTO.setTimeType(ClockPointEnum.BEFORE);
                        }
                    }
                    toRestClockPointDTO.setElasticTime(null);
                    endRestClockPointDTO.setElasticTime(null);
                }

                if (endRestClockPointDTO.getTimeType() == ClockPointEnum.EMPTY || endRestClockPointDTO.getClockTime() == null){
                    //当弹性结束未匹配到打卡，弹性失效，进行还原

                    restSchedule.put("dtkssj",toRestClockPointDTO.getClassTime().split(" ")[1]);
                    restSchedule.put("dtjssj",endRestClockPointDTO.getClassTime().split(" ")[1]);

                    //重新设置打卡时间
                    toRestIndex = needClockDateList.indexOf(toRestClockPointDTO.getElasticTime());
                    needClockDateList.remove(toRestIndex);
                    needClockDateList.add(toRestIndex,toRestClockPointDTO.getClassTime());

                    endRestIndex = needClockDateList.indexOf(endRestClockPointDTO.getElasticTime());
                    needClockDateList.remove(endRestIndex);
                    needClockDateList.add(endRestIndex,endRestClockPointDTO.getClassTime());
                    if (toRestClockPointDTO.getClockTime() != null){
                        String time = toRestClockPointDTO.getClockTime().get("signdate")+" "+toRestClockPointDTO.getClockTime().get("signtime");
                        if (DateUtil.getTime(time).compareTo(DateUtil.getTime(toRestClockPointDTO.getClassTime())) > 0){
                            toRestClockPointDTO.setTimeType(ClockPointEnum.AFTER);
                        }else if (DateUtil.getTime(time).compareTo(DateUtil.getTime(toRestClockPointDTO.getClassTime())) ==0){
                            toRestClockPointDTO.setTimeType(ClockPointEnum.EQUAL);
                        }else {
                            toRestClockPointDTO.setTimeType(ClockPointEnum.BEFORE);
                        }
                    }
                    toRestClockPointDTO.setElasticTime(null);
                    endRestClockPointDTO.setElasticTime(null);
                }
            }

        }

    }


    /**
     * 获取开始打卡的打卡数据在卡点的位置
     * @param needClockIn
     * @param ksdkNearestClcokInTime
     * @return
     */
    public ClockPointEnum getStartClassTimeType(Map<String, Object> needClockIn,Map<ClockPointEnum, Map<String, Object>> ksdkNearestClcokInTime,String dtkssj,String minelasticTime){

        int tqdkfzs = 60;
        if (Util.null2String(needClockIn.get("tqdkfzs")).equals("") && !"".equals(getBeforeClockTime(needClockDateList,dtkssj))){
            tqdkfzs = DateUtil.getBetWeenMinutes(getBeforeClockTime(needClockDateList,dtkssj),dtkssj);
        }else {

            tqdkfzs = Util.null2String(needClockIn.get("tqdkfzs")).equals("")?60:Integer.valueOf(needClockIn.get("tqdkfzs").toString());
        }
        ClockPointEnum timeType = ClockPointEnum.EMPTY;
        if (ksdkNearestClcokInTime.get(ClockPointEnum.EQUAL) != null) {
            timeType = ClockPointEnum.EQUAL;
        }
        if (ClockPointEnum.EMPTY.equals(timeType) && ksdkNearestClcokInTime.get(ClockPointEnum.BEFORE) != null) {
            String clockInTime = ksdkNearestClcokInTime.get(ClockPointEnum.BEFORE).get("signdate") + " " + ksdkNearestClcokInTime.get(ClockPointEnum.BEFORE).get("signtime");
            /*if (DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(DateUtil.beforeMinutes(minelasticTime, tqdkfzs))) >= 0 &&
                    (getBeforeClockTime(needClockDateList,dtkssj).equals("") || DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(getBeforeClockTime(needClockDateList,dtkssj))) > 0)) {
                //打卡时间大于等于最早打卡时间
                timeType = ClockPointEnum.BEFORE;
            }*/
            if (DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(DateUtil.beforeMinutes(minelasticTime, tqdkfzs))) >= 0) {
                //打卡时间大于等于最早打卡时间
                timeType = ClockPointEnum.BEFORE;
            }
        }
        if (ClockPointEnum.EMPTY.equals(timeType) && ksdkNearestClcokInTime.get(ClockPointEnum.AFTER) != null) {
            String clockInTime = ksdkNearestClcokInTime.get(ClockPointEnum.AFTER).get("signdate") + " " + ksdkNearestClcokInTime.get(ClockPointEnum.AFTER).get("signtime");

            if (getNextClockTime(needClockDateList,dtkssj).equals("") || DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(getNextClockTime(needClockDateList,dtkssj))) < 0) {
                //打卡时间小于结束时间
                timeType = ClockPointEnum.AFTER;
            }
        }
        return timeType;
    }

    /**
     * 获取结束打卡的打卡数据在卡点的位置
     * @param needClockIn
     * @param jsdkNearestClcokInTime
     * @return
     */
    public ClockPointEnum getEndClassTimeType(Map<String, Object> needClockIn,Map<ClockPointEnum, Map<String, Object>> jsdkNearestClcokInTime,String dtjssj,String maxelasticTime){

        int thdkfzs = 60;
        if (Util.null2String(needClockIn.get("thdkfzs")).equals("") && !"".equals(getNextClockTime(needClockDateList,dtjssj))){
            thdkfzs = DateUtil.getBetWeenMinutes(dtjssj,getNextClockTime(needClockDateList,dtjssj));
        }else {
            thdkfzs = Util.null2String(needClockIn.get("thdkfzs")).equals("")?60:Integer.valueOf(needClockIn.get("thdkfzs").toString());
        }

        ClockPointEnum timeType = ClockPointEnum.EMPTY;

        if (jsdkNearestClcokInTime.get(ClockPointEnum.EQUAL) != null) {
            timeType = ClockPointEnum.EQUAL;
        }
        if (ClockPointEnum.EMPTY.equals(timeType) && jsdkNearestClcokInTime.get(ClockPointEnum.AFTER) != null) {
            String clockInTime = jsdkNearestClcokInTime.get(ClockPointEnum.AFTER).get("signdate") + " " + jsdkNearestClcokInTime.get(ClockPointEnum.AFTER).get("signtime");
            /*if (DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(DateUtil.AfterMinutes(maxelasticTime, thdkfzs))) <= 0 &&
                    (getNextClockTime(needClockDateList,dtjssj).equals("") || DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(getNextClockTime(needClockDateList,dtjssj))) < 0)) {
                timeType = ClockPointEnum.AFTER;
            }*/

            if (DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(DateUtil.AfterMinutes(maxelasticTime, thdkfzs))) <= 0) {
                timeType = ClockPointEnum.AFTER;
            }
        }
        if (ClockPointEnum.EMPTY.equals(timeType) && jsdkNearestClcokInTime.get(ClockPointEnum.BEFORE) != null) {
            String clockInTime = jsdkNearestClcokInTime.get(ClockPointEnum.BEFORE).get("signdate") + " " + jsdkNearestClcokInTime.get(ClockPointEnum.BEFORE).get("signtime");
            if (getBeforeClockTime(needClockDateList,dtjssj).equals("") || DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(getBeforeClockTime(needClockDateList,dtjssj))) > 0) {
                timeType = ClockPointEnum.BEFORE;
            }
        }
        return timeType;
    }
    public String getNextClockTime(List<String> needClockDateList,String time){
        int index = 0;
        for (int i=0;i<needClockDateList.size();i++){
            if (needClockDateList.get(i).equals(time)){
                index = i+1;
                break;
            }
            /*if (DateUtil.getTime(time).compareTo(DateUtil.getTime(needClockDateList.get(i))) <= 0) {
                index = i;
                break;
            }*/
        }
        if (index < needClockDateList.size() && index!=0){
            return needClockDateList.get(index);
        }else {
            return "";
        }
    }

    public String getBeforeClockTime(List<String> needClockDateList,String time){
        int index = 0;
        for (int i=0;i<needClockDateList.size();i++){
            if (needClockDateList.get(i).equals(time)){
                index = i-1;
                break;
            }
        }
        if (index >= 0){
            return needClockDateList.get(index);
        }else {
            return "";
        }
    }
    /**
     * 判断是否是工作（包含加班）类型时段
     * @param classSegmentType
     * @return
     */
    public boolean ifWorkClassSegment(String classSegmentType){
        if (classSegmentType.equals(ClassSegmentTypeEnum.WORK_TIME.getKey()) || classSegmentType.equals(ClassSegmentTypeEnum.EXTENDED_OVERTIME.getKey())
                ||classSegmentType.equals(ClassSegmentTypeEnum.OVERTIME_PLAN.getKey()) || classSegmentType.equals(ClassSegmentTypeEnum.EARLY_OVERTIME.getKey()) || classSegmentType.equals(ClassSegmentTypeEnum.OVERTIME_IN_CLASS.getKey())){
            return true;
        }else {
            return false;
        }
    }

    public ClockPointEnum getTimeType(ClockPointDTO clockPointDTO,Map<String,Object> clockInMap){
        if (clockInMap == null){
            return ClockPointEnum.EMPTY;
        }
        String clockInTime  = clockInMap.get("signdate")+ " "+clockInMap.get("signtime");
        int compare = DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(clockPointDTO.getClassTime()));
        if (compare == 0){
            return ClockPointEnum.EQUAL;
        }else if (compare > 0){
            return ClockPointEnum.AFTER;
        }else {
            return ClockPointEnum.BEFORE;
        }
    }
}
